package yun.web.activerecord.tx;

import cn.hutool.core.util.ReflectUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.aop.ProxyMethodInvocation;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import yun.web.activerecord.Db;
import yun.web.activerecord.DbPro;

@Conditional(TxEnableCondition.class)
@EnableAspectJAutoProxy
@Component
@Aspect
public class TxConfig {

    // Cache 注解和 Tx 注解 不能同时存在于一个方法
    @Around("@annotation(yun.web.activerecord.tx.Tx) && !@annotation(yun.web.cache.Cache)")
    public Object tx(ProceedingJoinPoint pjp) throws Throwable {
        ProxyMethodInvocation methodInvocation = (ProxyMethodInvocation) ReflectUtil.getFieldValue(pjp, "methodInvocation");


        Tx tx = methodInvocation.getMethod().getAnnotation(Tx.class);
        String configName = tx.configName();
        DbPro dbPro = configName.equals("") ? Db.use() : Db.use(configName);
        Object[] o = {null};
        Throwable[] ea = {null};
        boolean b = dbPro.tx(() -> {
            try {
                o[0] = pjp.proceed(pjp.getArgs());
            } catch (Throwable e) {
                ea[0] = e;
                if (e instanceof RuntimeException) {
                    throw (RuntimeException) e;
                } else {
                    // throw ea[0];
                    throw new RuntimeException(e.getCause());
                }
                //
            }
            return true;
        });
        if (b) {
            return o[0];
        } else {
            throw ea[0];
        }
    }
}
